package com.theorydance.esoperator.plugin;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import cn.hutool.core.util.ArrayUtil;
import com.theorydance.esoperator.utils.EsUtils;

/**
 * ES的mapper代理工具类
 * @author TheoryDance
 */
public class EsProxy implements InvocationHandler{

	/**
	 * 存放所有的dsl映射关系
	 */
	public final static Map<String, EsMethodDefinition> dslMap = new ConcurrentHashMap<>();

	/**
	 * 获取es mapper代理对象
	 * @param clazz 定义获取es数据的mapper接口类
	 */
	public static <T> T getProxy(Class<T> clazz) {
		@SuppressWarnings("unchecked")
		T proxyInstance = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] {clazz}, new EsProxy());
        return proxyInstance;
	}

	/**
	 * 判断target是否是array数组内的一个元素
	 */
	private boolean contain(Class<?>[] array, Class<?> target) {
		return Arrays.stream(array)
				.anyMatch(item -> item.toString().equals(target.toString()));
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 定义变量，用于存放传递的参数
		Map<String,Object> paramterMap = new HashMap<>(16);
		if(ArrayUtil.isNotEmpty(args)) {
			if(args.length==1 && args[0] instanceof  Map) {
				Map<? extends String,? extends Object> mm = (Map)args[0];
				paramterMap.putAll(mm);
			} else {
				// 获取参数的注解名称
		        List<Esparam> paramterAnnos = new ArrayList<>();
		        Annotation[][] lll = method.getParameterAnnotations();
		        for (Annotation[] annotations : lll) {
					for (Annotation annotation : annotations) {
						paramterAnnos.add((Esparam)annotation);
					}
				}

		        // 将传递的参数使用Map进行保存
		        Type[] paramterTypes = method.getGenericParameterTypes();
		        for(int i=0;i<paramterTypes.length;i++) {
		        	String key = paramterAnnos.get(i).value();
		        	Object value = args[i];
		        	paramterMap.put(key, value);
		        }
			}
		}

        // 先判断是否已经解析过，如果已经解析，则不需要进行重复解析
        String methodName = method.getDeclaringClass().getName()+"."+method.getName();
		// 从xml中得到该方法对应的dsl定义
		EsMethodDefinition dslDefine = dslMap.get(methodName);
        if(dslDefine == null) {
        	synchronized(EsProxy.class){
        		dslDefine = dslMap.get(methodName);
        		if(dslDefine == null){
        			// 解析该方法对应的xml文件；1.获取SAXParserFactory实例
            		SAXParserFactory factory = SAXParserFactory.newInstance();
					// 2.获取SAXparser实例
            		SAXParser saxParser = factory.newSAXParser();
					// 创建Handel对象
            		EsDSLPraseHandel handel = new EsDSLPraseHandel(method.getDeclaringClass().getName());
            		// 找到该方法对应的xml文件，要求xml文件与定义的方法在同一个目录中，且文件名相同，方法名相同
            		InputStream xmlFile = EsProxy.class.getResourceAsStream("/"+method.getDeclaringClass().getName().replace(".", "/")+".xml");
            		saxParser.parse(xmlFile, handel);
					// 从xml中得到该方法对应的dsl定义
            		dslDefine = dslMap.get(methodName);
        		}
        	}
        }
		// 得到查询条件及返回内容
        String dsl = dslDefine.getDsl();
        // 得到要查询的索引
        String esIndex = dslDefine.getEsIndex();
		// 处理索引中含有的${}变量
        esIndex = replaceVar(esIndex, paramterMap);
		// 得到要解析的响应结果
        String expression = dslDefine.getExpression();
		expression = replaceVar(expression, paramterMap);
		List<Map<String, Object>> list = EsUtils.getEsAggsData(esIndex, dsl, expression, paramterMap, paramterMap);
        return list;
	}

	/**
	 * 将字符串中的${var_name}替换为变量var_name的值
	 */
	private String replaceVar(String esIndex, Map<String, Object> paramterMap){
		if(!esIndex.contains("$")) {
			return esIndex;
		}
		for(String key: paramterMap.keySet()) {
			if(paramterMap.get(key)!=null) {
				esIndex = esIndex.replace("${"+key+"}", paramterMap.get(key).toString());
			}
		}
		return esIndex;
	}

}
